#pragma once
#include "Windows.h"
#include <queue>

class WorkQueue;

class WorkItemBase {
  virtual void work(void *context) = 0;
  virtual void abort() = 0;
  friend WorkQueue;
};

typedef std::queue<WorkItemBase *> WorkItemQueue, *PWorkItemQueue;

class WorkQueue {
public:
  virtual ~WorkQueue() {};
  bool create(const unsigned int num_of_threads,
              void **thread_data_array = NULL);
  bool insert_work_item(WorkItemBase *work_iterm);
  void destroy(int wait_seconds = 1);
  int get_threads_num();
  void suspend();
  void resume();

public:
  PHANDLE threads_;

private:
  static unsigned long __stdcall thread_func(void *param);
  WorkItemBase *remove_work_item();
  size_t get_work_queue_size();

  enum {
    ABORT_EVENT_INDEX = 0,
    SEMAPHORE_INDEX,
    NUMBER_OF_SYNC_OBJ,
  };

  unsigned int num_of_threads_;
  void *thread_data_array_;
  HANDLE sync_obj_array_[NUMBER_OF_SYNC_OBJ];

  CRITICAL_SECTION cs_;
  PWorkItemQueue work_item_queue_;
};
